package com.miaocat19.service.impl;

import com.miaocat19.dao.ItemDOMapper;
import com.miaocat19.dao.ItemStockDOMapper;
import com.miaocat19.dao.StockLogDOMapper;
import com.miaocat19.dataobject.ItemDO;
import com.miaocat19.dataobject.ItemStockDO;
import com.miaocat19.dataobject.StockLogDO;
import com.miaocat19.error.BusinessException;
import com.miaocat19.error.EmBusinessError;
import com.miaocat19.mq.MqProducer;
import com.miaocat19.service.ItemService;
import com.miaocat19.service.PromoService;
import com.miaocat19.service.model.ItemModel;
import com.miaocat19.service.model.PromoModel;
import com.miaocat19.validator.ValidationResult;
import com.miaocat19.validator.ValidatorImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Time;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @program: Javamiaosha
 * @description:
 * @author: miaocat19
 * @create: 2021-12-10 15:18
 **/
@Service
public class ItemServiceImpl implements ItemService {


    @Autowired
    private ValidatorImpl validatorImpl;

    @Autowired
    private ItemDOMapper itemMapper;

    @Autowired
    private ItemStockDOMapper itemStockDOMapper;

    @Autowired
    private PromoService promoService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private MqProducer producer;

    @Autowired
    private StockLogDOMapper stockLogDOMapper;

    @Override
    @Transactional
    public ItemModel createItem(ItemModel itemModel) throws BusinessException {

        ValidationResult result = validatorImpl.validate(itemModel);

        if (result.isHasErrors()) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, result.getErrMsg());
        }
        //转化itemmodel->dataobject
        ItemDO itemDO = this.convertItemDOFromItemModel(itemModel);
        itemMapper.insertSelective(itemDO);
        itemModel.setId(itemDO.getId());


        ItemStockDO itemStockDo = this.convertItemStockDOFromItemModel(itemModel);

        itemStockDOMapper.insertSelective(itemStockDo);


        return this.getItemById(itemModel.getId());
    }

    @Override
    public ItemModel getItemById(Integer id) {
        ItemDO itemDO = itemMapper.selectByPrimaryKey(id);
        if (itemDO == null) {
            return null;
        }

        //操作获得库存数量
        ItemStockDO itemStockDO = itemStockDOMapper.selectByItemId(itemDO.getId());

        //将dataobject->model
        ItemModel itemModel = convertModelFromDataObject(itemDO, itemStockDO);


        //获取活动商品信息
        PromoModel promoModel = promoService.getPromoByItemId(itemModel.getId());


        /**
         * 这里显示的事情是只要不是三就可以显示
         * */
        if (promoModel != null && promoModel.getStatus().intValue() != 3) {
            itemModel.setPromoModel(promoModel);
        }

        return itemModel;
    }


    @Override
    public ItemModel getItemByIdInCache(Integer id) {
        /*先从redis看看是不是有*/
        ItemModel itemModel = (ItemModel) redisTemplate.opsForValue().get("item_validate_" + id);

        if (itemModel == null) {
            itemModel = this.getItemById(id);
            redisTemplate.opsForValue().set("item_validate_" + id, itemModel);
            redisTemplate.expire("item_validate_" + id, 10, TimeUnit.MINUTES);
        }

        return itemModel;
    }


    @Override
    public List<ItemModel> listItem() {
        List<ItemDO> itemDOList = itemMapper.listItem();

        List<ItemModel> itemModelList = itemDOList.stream().map(itemDO -> {
            ItemStockDO itemStockDO = itemStockDOMapper.selectByItemId(itemDO.getId());
            return this.convertModelFromDataObject(itemDO, itemStockDO);
        }).collect(Collectors.toList());

        return itemModelList;
    }

    @Override
    @Transactional
    public boolean decreaseStock(Integer itemId, Integer amount) {
        /*刚才使用redis进行了缓存 所以我们要先减去reids中库存   然后要解决的就是数据库中的对应不一致的问题*/

        //int affectedRow = itemStockDOMapper.decreaseStock(itemId, amount);
        /*这个是减去redis中的库存    看是不是小于0  如果时的话 我们还要进行回溯*/
        long result = redisTemplate.opsForValue().increment("promo_item_stock_" + itemId, amount.intValue() * -1);

        if (result > 0) {
            //更新库存成功
            /*使用rocketmq进行异步减库存*/
           /* if (!producer.asyncReduceStock(itemId, amount)) {
                redisTemplate.opsForValue().increment("promo_item_stock_" + itemId, amount.intValue());
                return false;
            }*/

            return true;
        } else if (result == 0) {
            redisTemplate.opsForValue().set("promo_item_stock_invalid_" + itemId, "true");
            return true;
        } else {
            //更新库存失败
//            redisTemplate.opsForValue().increment("promo_item_stock_" + itemId, amount.intValue() * 1);
            increaseStock(itemId, amount);
            return false;
        }
    }


    @Override
    public boolean increaseStock(Integer itemId, Integer amount) {
        redisTemplate.opsForValue().increment("promo_item_stock_" + itemId, amount.intValue() * 1);
        return true;
    }

    @Override
    public boolean asyncDecreaseStock(Integer itemId, Integer amount) {

        boolean mqresult = producer.asyncReduceStock(itemId, amount);
        return mqresult;
    }

    @Override
    public void increaseSale(Integer itemId, Integer amount) {
        itemMapper.increaseSale(itemId, amount);
    }


    @Override
    public String initStockLog(Integer itemId, Integer amount) {
        StockLogDO stockLogDO = new StockLogDO();
        stockLogDO.setItemId(itemId);
        stockLogDO.setAmount(amount);
        stockLogDO.setStockLogId(UUID.randomUUID().toString().replace("-", ""));
        stockLogDO.setStatus(1);
        stockLogDOMapper.insertSelective(stockLogDO);
        return stockLogDO.getStockLogId();
    }


    private ItemModel convertModelFromDataObject(ItemDO itemDO, ItemStockDO itemStockDO) {
        ItemModel itemModel = new ItemModel();
        BeanUtils.copyProperties(itemDO, itemModel);
        itemModel.setPrice(new BigDecimal(itemDO.getPrice()));
        itemModel.setStock(itemStockDO.getStock());

        return itemModel;
    }


    private ItemStockDO convertItemStockDOFromItemModel(ItemModel itemModel) {
        if (itemModel == null) {
            return null;
        }
        ItemStockDO itemStockDO = new ItemStockDO();
        itemStockDO.setItemId(itemModel.getId());
        itemStockDO.setStock(itemModel.getStock());

        return itemStockDO;
    }


    private ItemDO convertItemDOFromItemModel(ItemModel itemModel) {
        if (itemModel == null) {
            return null;
        }
        ItemDO itemDO = new ItemDO();
        BeanUtils.copyProperties(itemModel, itemDO);
        itemDO.setPrice(itemModel.getPrice().doubleValue());
        return itemDO;
    }
}
